home *** CD-ROM | disk | FTP | other *** search
/ The Mac Mega CD - Killer Software / The Mac Mega CD - Killer Software (May 1996).dmg / Shareware City / Sound / MacMikMod 2.10+src / source / virtch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-04  |  17.1 KB  |  854 lines  |  [TEXT/CWIE]

  1. /*
  2.  
  3. Name:
  4. VIRTCH.C
  5.  
  6. Description:
  7. All-c sample mixing routines, using a 32 bits mixing buffer
  8.  
  9. Portability:
  10. All systems - all compilers
  11.  
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include "mikmod.h"
  17.  
  18. #define FRACBITS 11
  19. #define FRACMASK ((1L<<FRACBITS)-1)
  20.  
  21. #define TICKLSIZE 3600
  22. #define TICKWSIZE (TICKLSIZE*2)
  23. #define TICKBSIZE (TICKWSIZE*2)
  24. static SLONG VC_TICKBUF[TICKLSIZE];
  25.  
  26. #ifndef min
  27. #define min(a,b) (((a)<(b)) ? (a) : (b))
  28. #endif
  29.  
  30. typedef struct{
  31.     UBYTE kick;                     /* =1 -> sample has to be restarted */
  32.     UBYTE active;                   /* =1 -> sample is playing */
  33.     UWORD flags;                    /* 16/8 bits looping/one-shot */
  34.     SWORD handle;                  /* identifies the sample */
  35.     ULONG start;                    /* start index */
  36.     ULONG size;                     /* samplesize */
  37.     ULONG reppos;                   /* loop start */
  38.     ULONG repend;                   /* loop end */
  39.     ULONG frq;                      /* current frequency */
  40.     UBYTE vol;                      /* current volume */
  41.     UBYTE pan;                        /* current panning position */
  42.     SLONG current;                  /* current index in the sample */
  43.     SLONG increment;                 /* fixed-point increment value */
  44. #ifdef __WATCOMC__
  45.     UWORD lvolsel;                    /* left volume table selector */
  46.     UWORD rvolsel;                    /* right volume table selector */
  47. #else
  48.     SLONG lvolmul;                    /* left volume multiply */
  49.     SLONG rvolmul;                    /* right volume multiply */
  50. #endif
  51. } VINFO;
  52.  
  53.  
  54. static VINFO vinf[32];
  55. static VINFO *vnf;
  56.  
  57. static UWORD samplesthatfit;
  58. static SLONG idxsize,idxlpos,idxlend,maxvol;
  59.  
  60. static long per256;
  61. static int ampshift;
  62.  
  63.  
  64. #ifdef __WATCOMC__
  65.  
  66. static SLONG voltab[65][256];
  67. static UWORD volsel[65];
  68.  
  69. #ifdef __cplusplus
  70. extern "C" {
  71. #endif
  72.  
  73. UWORD lvolsel,rvolsel;
  74.  
  75. void AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);
  76. #pragma aux AsmStereoNormal    \
  77.         parm [esi] [edi] [ebx] [ecx] [edx] \
  78.         modify [eax];
  79.  
  80.  
  81. void AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);
  82. #pragma aux AsmMonoNormal     \
  83.         parm [esi] [edi] [ebx] [ecx] [edx] \
  84.         modify [eax];
  85.  
  86. #ifdef __cplusplus
  87. }
  88. #endif
  89.  
  90. void freedescriptor(unsigned short selector);
  91. #pragma aux freedescriptor =    \
  92.     "mov    ax,0001h"       \
  93.     "int    31h"            \
  94.     parm    [bx]            \
  95.     modify  [ax];
  96.  
  97. unsigned short getalias(void);
  98. #pragma aux getalias =          \
  99.     "mov    ax,cs   "       \
  100.     "mov    bx,ax   "       \
  101.     "mov    ax,000ah"       \
  102.     "int    31h     "       \
  103.     "jnc    isok    "       \
  104.     "xor    ax,ax   "       \
  105.     "isok:          "       \
  106.     modify  [bx]            \
  107.     value   [ax];
  108.  
  109. void setbase(unsigned short selector,unsigned long offset);
  110. #pragma aux setbase =           \
  111.     "mov    ax,0007h"       \
  112.     "mov    ecx,edx"        \
  113.     "ror    ecx,16"         \
  114.     "int    31h"            \
  115.     parm    [bx] [edx]      \
  116.     modify  [ax ecx] ;
  117.  
  118. void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift);
  119. #pragma aux VC_Sample32To16Copy =    \
  120. "again:"                    \
  121.     "mov   eax,[esi]"        \
  122.     "sar   eax,cl"          \
  123.     "cmp   eax,32767"        \
  124.     "jg    toobig"             \
  125.     "cmp   eax,-32768"        \
  126.     "jl    toosmall"        \
  127. "write:"                    \
  128.     "mov   [edi],ax"        \
  129.     "add   esi,4"           \
  130.     "add   edi,2"            \
  131.     "dec   edx"               \
  132.     "jnz   again"           \
  133.     "jmp   ready"            \
  134. "toobig:"                   \
  135.     "mov   eax,32767"        \
  136.     "jmp   write"            \
  137. "toosmall:"                 \
  138.     "mov   eax,-32768"        \
  139.     "jmp   write"            \
  140. "ready:"                    \
  141.     parm [esi] [edi] [edx] [cl]    \
  142.     modify [eax] ;
  143.  
  144.  
  145. void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift);
  146. #pragma aux VC_Sample32To8Copy =    \
  147. "again:"                       \
  148.     "mov   eax,[esi]"           \
  149.     "sar   eax,cl"          \
  150.     "cmp   eax,127"         \
  151.     "jg    toobig"             \
  152.     "cmp   eax,-128"        \
  153.     "jl    toosmall"        \
  154. "write:"                    \
  155.     "add   al,080h"         \
  156.     "mov   [edi],al"        \
  157.     "add   esi,4"           \
  158.     "inc   edi"             \
  159.     "dec   edx"             \
  160.     "jnz   again"            \
  161.     "jmp   ready"            \
  162. "toobig:"                   \
  163.     "mov   eax,127"         \
  164.     "jmp   write"            \
  165. "toosmall:"                 \
  166.     "mov   eax,-128"        \
  167.     "jmp   write"            \
  168. "ready:"                    \
  169.     parm [esi] [edi] [edx] [cl]    \
  170.     modify [eax] ;
  171.  
  172.  
  173. #else
  174.  
  175.  
  176. static SLONG lvolmul,rvolmul;
  177.  
  178.  
  179. static void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift)
  180. {
  181.     // [DEMOS]-> shift renamed to _shift to avoid variable collision
  182.     SLONG c;
  183.     int _shift=(24-ampshift);
  184.  
  185.     while(count--){
  186.         c=*srce >> _shift;
  187.         if(c>127) c=127;
  188.         else if(c<-128) c=-128;
  189.         *dest++=c+128;
  190.         srce++;
  191.     }
  192. }
  193.  
  194.  
  195. static void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift)
  196. {
  197.     // [DEMOS]-> shift renamed to _shift to avoid variable collision
  198.     SLONG c;
  199.     int _shift=(16-ampshift);
  200.  
  201.     while(count--){
  202.         c=*srce >> _shift;
  203.         if(c>32767) c=32767;
  204.         else if(c<-32768) c=-32768;
  205.         *dest++=c;
  206.         srce++;
  207.     }
  208. }
  209.  
  210. #endif
  211.  
  212.  
  213. static SLONG fraction2long(ULONG dividend,UWORD divisor)
  214. /*
  215.     Converts the fraction 'dividend/divisor' into a fixed point longword.
  216. */
  217. {
  218.     ULONG whole,part;
  219.  
  220.     whole=dividend/divisor;
  221.     part=((dividend%divisor)<<FRACBITS)/divisor;
  222.  
  223.     return((whole<<FRACBITS)|part);
  224. }
  225.  
  226.  
  227. static UWORD samples2bytes(UWORD samples)
  228. {
  229.     if(md_mode & DMODE_16BITS) samples<<=1;
  230.     if(md_mode & DMODE_STEREO) samples<<=1;
  231.     return samples;
  232. }
  233.  
  234.  
  235. static UWORD bytes2samples(UWORD bytes)
  236. {
  237.     if(md_mode & DMODE_16BITS) bytes>>=1;
  238.     if(md_mode & DMODE_STEREO) bytes>>=1;
  239.     return bytes;
  240. }
  241.  
  242.  
  243. /**************************************************
  244. ***************************************************
  245. ***************************************************
  246. **************************************************/
  247.  
  248.  
  249. static SBYTE *Samples[MAXSAMPLEHANDLES];
  250.  
  251.  
  252. BOOL LargeRead(SBYTE *buffer,ULONG size)
  253. {
  254.     int t;
  255.     ULONG todo;
  256.  
  257.     while(size){
  258.         /* how many bytes to load (in chunks of 8000) ? */
  259.  
  260.         todo=(size>8000)?8000:size;
  261.  
  262.         /* read data */
  263.  
  264.         SL_Load(buffer,todo);
  265.         /* and update pointers.. */
  266.  
  267.         size-=todo;
  268.         buffer+=todo;
  269.     }
  270.     return 1;
  271. }
  272.  
  273.  
  274.  
  275. SWORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags)
  276. {
  277.     int handle;
  278.     ULONG t;
  279.  
  280.     SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS);
  281.  
  282.     /* Find empty slot to put sample address in */
  283.  
  284.     for(handle=0;handle<MAXSAMPLEHANDLES;handle++){
  285.         if(Samples[handle]==NULL) break;
  286.     }
  287.  
  288.     if(handle==MAXSAMPLEHANDLES){
  289.         myerr=ERROR_OUT_OF_HANDLES;
  290.         return -1;
  291.     }
  292.  
  293.         if((Samples[handle]=(SBYTE *)malloc(length+16))==NULL){
  294.         myerr=ERROR_SAMPLE_TOO_BIG;
  295.         return -1;
  296.     }
  297.  
  298.     /* read sample into buffer. */
  299.     LargeRead(Samples[handle],length);
  300.  
  301.     /* Unclick samples: */
  302.  
  303.     if(flags & SF_LOOP){
  304.         if(flags & SF_BIDI)
  305.             for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][(repend-t)-1];
  306.         else
  307.             for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][t+reppos];
  308.     }
  309.     else{
  310.         for(t=0;t<16;t++) Samples[handle][t+length]=0;
  311.     }
  312.  
  313.     return handle;
  314. }
  315.  
  316.  
  317.  
  318. void VC_SampleUnload(SWORD handle)
  319. {
  320.     void *sampleadr=Samples[handle];
  321.  
  322.     free(sampleadr);
  323.     Samples[handle]=NULL;
  324. }
  325.  
  326.  
  327. /**************************************************
  328. ***************************************************
  329. ***************************************************
  330. **************************************************/
  331.  
  332.  
  333. #ifndef __WATCOMC__
  334.  
  335.  
  336. static void (*SampleMix)(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo);
  337.  
  338.  
  339. static void MixStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  340. {
  341.     SBYTE sample;
  342.  
  343.     while(todo>0){
  344.         sample=srce[index>>FRACBITS];
  345.         *(dest++)+=lvolmul*sample;
  346.         *(dest++)+=rvolmul*sample;
  347.         index+=increment;
  348.         todo--;
  349.     }
  350. }
  351.  
  352.  
  353. static void MixMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  354. {
  355.     SBYTE sample;
  356.  
  357.     while(todo>0){
  358.         sample=srce[index>>FRACBITS];
  359.         *(dest++)+=lvolmul*sample;
  360.         index+=increment;
  361.         todo--;
  362.     }
  363. }
  364.  
  365.  
  366. static void MixStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  367. {
  368.     SWORD sample,a,b;
  369.  
  370.     while(todo>0){
  371.         a=srce[index>>FRACBITS];
  372.         b=srce[1+(index>>FRACBITS)];
  373.         sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);
  374.  
  375.         *(dest++)+=lvolmul*sample;
  376.         *(dest++)+=rvolmul*sample;
  377.         index+=increment;
  378.         todo--;
  379.     }
  380. }
  381.  
  382.  
  383. static void MixMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  384. {
  385.     SWORD sample,a,b;
  386.  
  387.     while(todo>0){
  388.         a=srce[index>>FRACBITS];
  389.         b=srce[1+(index>>FRACBITS)];
  390.         sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);
  391.  
  392.         *(dest++)+=lvolmul*sample;
  393.  
  394.         index+=increment;
  395.         todo--;
  396.     }
  397. }
  398.  
  399. #endif
  400.  
  401.  
  402. static UWORD NewPredict(SLONG index,SLONG end,SLONG increment,UWORD todo)
  403. /*
  404.     This functions returns the number of resamplings we can do so that:
  405.  
  406.         - it never accesses indexes bigger than index 'end'
  407.         - it doesn't do more than 'todo' resamplings
  408. */
  409. {
  410.     SLONG di;
  411.  
  412.     di=(end-index)/increment;
  413.     index+=(di*increment);
  414.  
  415.     if(increment<0){
  416.         while(index>=end){
  417.             index+=increment;
  418.             di++;
  419.         }
  420.     }
  421.     else{
  422.         while(index<=end){
  423.             index+=increment;
  424.             di++;
  425.         }
  426.     }
  427.     return ((di<todo) ? di : todo);
  428. }
  429.  
  430.  
  431. static void VC_AddChannel(SLONG *ptr,UWORD todo)
  432. /*
  433.     Mixes 'todo' stereo or mono samples of the current channel to the tickbuffer.
  434. */
  435. {
  436.     SLONG end;
  437.     UWORD done,needs;
  438.         SBYTE *s;
  439.  
  440.     while(todo>0){
  441.  
  442.         /* update the 'current' index so the sample loops, or
  443.            stops playing if it reached the end of the sample */
  444.  
  445.         if(vnf->flags&SF_REVERSE){
  446.  
  447.             /* The sample is playing in reverse */
  448.  
  449.                 if(vnf->flags&SF_LOOP){
  450.  
  451.                     /* the sample is looping, so check if
  452.                        it reached the loopstart index */
  453.  
  454.                     if(vnf->current<idxlpos){
  455.                     if(vnf->flags&SF_BIDI){
  456.  
  457.                         /* sample is doing bidirectional loops, so 'bounce'
  458.                             the current index against the idxlpos */
  459.  
  460.                         vnf->current=idxlpos+(idxlpos-vnf->current);
  461.                         vnf->flags&=~SF_REVERSE;
  462.                         vnf->increment=-vnf->increment;
  463.                     }
  464.                     else
  465.                         /* normal backwards looping, so set the
  466.                             current position to loopend index */
  467.  
  468.                             vnf->current=idxlend-(idxlpos-vnf->current);
  469.                     }
  470.                 }
  471.                 else{
  472.  
  473.                     /* the sample is not looping, so check
  474.                         if it reached index 0 */
  475.  
  476.                     if(vnf->current<0){
  477.  
  478.                         /* playing index reached 0, so stop
  479.                             playing this sample */
  480.  
  481.                         vnf->current=0;
  482.                         vnf->active=0;
  483.                         break;
  484.                     }
  485.                 }
  486.         }
  487.         else{
  488.  
  489.             /* The sample is playing forward */
  490.  
  491.                 if(vnf->flags&SF_LOOP){
  492.  
  493.                     /* the sample is looping, so check if
  494.                         it reached the loopend index */
  495.  
  496.                     if(vnf->current>idxlend){
  497.                         if(vnf->flags&SF_BIDI){
  498.  
  499.                         /* sample is doing bidirectional loops, so 'bounce'
  500.                             the current index against the idxlend */
  501.  
  502.                             vnf->flags|=SF_REVERSE;
  503.                             vnf->increment=-vnf->increment;
  504.                             vnf->current=idxlend-(vnf->current-idxlend); /* ?? */
  505.                         }
  506.                         else
  507.                         /* normal backwards looping, so set the
  508.                             current position to loopend index */
  509.  
  510.                             vnf->current=idxlpos+(vnf->current-idxlend);
  511.                     }
  512.                 }
  513.                 else{
  514.  
  515.                     /* sample is not looping, so check
  516.                         if it reached the last position */
  517.  
  518.                     if(vnf->current>idxsize){
  519.  
  520.                         /* yes, so stop playing this sample */
  521.  
  522.                         vnf->current=0;
  523.                         vnf->active=0;
  524.                         break;
  525.                     }
  526.                 }
  527.         }
  528.  
  529.         /* Vraag een far ptr op van het sampleadres
  530.             op byte offset vnf->current, en hoeveel samples
  531.             daarvan geldig zijn (VOORDAT segment overschrijding optreed) */
  532.  
  533.         if(!(s=Samples[vnf->handle])){
  534.             vnf->current=0;
  535.             vnf->active=0;
  536.             break;
  537.         }
  538.  
  539.         if(vnf->flags & SF_REVERSE)
  540.             end = (vnf->flags & SF_LOOP) ? idxlpos : 0;
  541.         else
  542.             end = (vnf->flags & SF_LOOP) ? idxlend : idxsize;
  543.  
  544.         /* Als de sample simpelweg niet beschikbaar is, of als
  545.             sample gestopt moet worden sample stilleggen en stoppen */
  546.         /* mix 'em: */
  547.  
  548.         done=NewPredict(vnf->current,end,vnf->increment,todo);
  549.  
  550.         if(!done){
  551. /*            printf("predict stopped it. current %ld, end %ld\n",vnf->current,end);
  552. */            vnf->active=0;
  553.             break;
  554.         }
  555.  
  556.         /* optimisation: don't mix anything if volume is zero */
  557.  
  558.         if(vnf->vol){
  559. #ifdef __WATCOMC__
  560.             if(md_mode & DMODE_STEREO)
  561.                 AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done);
  562.             else
  563.                 AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done);
  564. #else
  565.             SampleMix(s,ptr,vnf->current,vnf->increment,done);
  566. #endif
  567.         }
  568.         vnf->current+=(vnf->increment*done);
  569.  
  570.         todo-=done;
  571.         ptr+=(md_mode & DMODE_STEREO) ? (done<<1) : done;
  572.     }
  573. }
  574.  
  575.  
  576.  
  577.  
  578. static void VC_FillTick(SBYTE *buf,UWORD todo)
  579. /*
  580.     Mixes 'todo' samples to 'buf'.. The number of samples has
  581.     to fit into the tickbuffer.
  582. */
  583. {
  584.     int t;
  585.  
  586.     /* clear the mixing buffer: */
  587.  
  588.     memset(VC_TICKBUF,0,(md_mode & DMODE_STEREO) ? todo<<3 : todo<<2);
  589.  
  590.     for(t=0;t<md_numchn;t++){
  591.         vnf=&vinf[t];
  592.  
  593.         if(vnf->active){
  594.             idxsize=(vnf->size<<FRACBITS)-1;
  595.             idxlpos=vnf->reppos<<FRACBITS;
  596.             idxlend=(vnf->repend<<FRACBITS)-1;
  597. #ifdef __WATCOMC__
  598.                         lvolsel=vnf->lvolsel;
  599.                         rvolsel=vnf->rvolsel;
  600. #else
  601.             lvolmul=vnf->lvolmul;
  602.             rvolmul=vnf->rvolmul;
  603. #endif
  604.             VC_AddChannel(VC_TICKBUF,todo);
  605.         }
  606.     }
  607.  
  608.     if(md_mode & DMODE_16BITS)
  609.         VC_Sample32To16Copy(VC_TICKBUF,(SWORD *)buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,16-ampshift);
  610.     else
  611.         VC_Sample32To8Copy(VC_TICKBUF,buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,24-ampshift);
  612. }
  613.  
  614.  
  615.  
  616. static void VC_WritePortion(SBYTE *buf,UWORD todo)
  617. /*
  618.     Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the
  619.     number of samples that fit into VC_TICKBUF, the mixing operation is split
  620.     up into a number of smaller chunks.
  621. */
  622. {
  623.     UWORD part;
  624.  
  625.     /* write 'part' samples to the buffer */
  626.  
  627.     while(todo){
  628.         part=min(todo,samplesthatfit);
  629.         VC_FillTick(buf,part);
  630.         buf+=samples2bytes(part);
  631.         todo-=part;
  632.     }
  633. }
  634.  
  635.  
  636. static UWORD TICKLEFT;
  637.  
  638.  
  639. void VC_WriteSamples(SBYTE *buf,UWORD todo)
  640. {
  641.     int t;
  642.     UWORD part;
  643.  
  644.     while(todo>0){
  645.  
  646.         if(TICKLEFT==0){
  647.             md_player();
  648.  
  649.             TICKLEFT=(125L*md_mixfreq)/(50L*md_bpm);
  650.  
  651.             /* compute volume, frequency counter & panning parameters for each channel. */
  652.  
  653.             for(t=0;t<md_numchn;t++){
  654.                 int pan,vol,lvol,rvol;
  655.  
  656.                 if(vinf[t].kick){
  657.                     vinf[t].current=(vinf[t].start << FRACBITS);
  658.                     vinf[t].active=1;
  659.                     vinf[t].kick=0;
  660.                 }
  661.  
  662.                 if(vinf[t].frq==0) vinf[t].active=0;
  663.  
  664.                 if(vinf[t].active){
  665.                     vinf[t].increment=fraction2long(vinf[t].frq,md_mixfreq);
  666.  
  667.                     if(vinf[t].flags & SF_REVERSE) vinf[t].increment=-vinf[t].increment;
  668.  
  669.                     vol=vinf[t].vol;
  670.                     pan=vinf[t].pan;
  671.  
  672. #ifdef __WATCOMC__
  673.                     if(md_mode & DMODE_STEREO){
  674.                         lvol= ( vol * (255-pan) ) / 255;
  675.                         rvol= ( vol * pan ) / 255;
  676.                         vinf[t].lvolsel=volsel[lvol];
  677.                         vinf[t].rvolsel=volsel[rvol];
  678.                     }
  679.                     else{
  680.                         vinf[t].lvolsel=volsel[vol];
  681.                     }
  682. #else
  683.                     if(md_mode & DMODE_STEREO){
  684.                         lvol= (( vol * (255-pan) ) / 255) << 1;
  685.                         rvol= (( vol * pan ) / 255) << 1;
  686.                         vinf[t].lvolmul=(maxvol*lvol)/64;
  687.                         vinf[t].rvolmul=(maxvol*rvol)/64;
  688.                     }
  689.                     else{
  690.                         vinf[t].lvolmul=(maxvol*vol)/64;
  691.                     }
  692. #endif
  693.                 }
  694.             }
  695.         }
  696.  
  697.         part=min(TICKLEFT,todo);
  698.  
  699.         VC_WritePortion(buf,part);
  700.  
  701.         TICKLEFT-=part;
  702.         todo-=part;
  703.  
  704.         buf+=samples2bytes(part);
  705.     }
  706. }
  707.  
  708.  
  709. UWORD VC_WriteBytes(SBYTE *buf,UWORD todo)
  710. /*
  711.     Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of
  712.     SBYTES actually written to 'buf' (which is rounded to number of samples
  713.     that fit into 'todo' bytes).
  714. */
  715. {
  716.     todo=bytes2samples(todo);
  717.     VC_WriteSamples(buf,todo);
  718.     return samples2bytes(todo);
  719. }
  720.  
  721.  
  722. void VC_SilenceBytes(SBYTE *buf,UWORD todo)
  723. /*
  724.     Fill the buffer with 'todo' bytes of silence (it depends on the mixing
  725.     mode how the buffer is filled)
  726. */
  727. {
  728.     /* clear the buffer to zero (16 bits
  729.        signed ) or 0x80 (8 bits unsigned) */
  730.  
  731.     if(md_mode & DMODE_16BITS)
  732.         memset(buf,0,todo);
  733.     else
  734.         memset(buf,0x80,todo);
  735. }
  736.  
  737.  
  738. void VC_PlayStart(void)
  739. {
  740.     int t;
  741.  
  742.     maxvol=16777216L / md_numchn;
  743.  
  744. #ifdef __WATCOMC__
  745.     for(t=0;t<65;t++){
  746.         int c;
  747.         SLONG volmul=(maxvol*t)/64;
  748.         for(c=-128;c<128;c++){
  749.             voltab[t][(UBYTE)c]=(SLONG)c*volmul;
  750.         }
  751.     }
  752. #endif
  753.  
  754.     /* instead of using a amplifying lookup table, I'm using a simple shift
  755.        amplify now.. amplifying doubles with every extra 4 channels, and also
  756.        doubles in stereo mode.. this seems to give similar volume levels
  757.        across the channel range */
  758.  
  759.     ampshift=md_numchn/8;
  760.     if(md_mode & DMODE_STEREO) ampshift++;
  761.  
  762. #ifndef __WATCOMC__
  763.     if(md_mode & DMODE_INTERP)
  764.         SampleMix=(md_mode & DMODE_STEREO) ? MixStereoInterp : MixMonoInterp;
  765.     else
  766.         SampleMix=(md_mode & DMODE_STEREO) ? MixStereoNormal : MixMonoNormal;
  767. #endif
  768.  
  769.     samplesthatfit=TICKLSIZE;
  770.     if(md_mode & DMODE_STEREO) samplesthatfit>>=1;
  771.     TICKLEFT=0;
  772. }
  773.  
  774.  
  775. void VC_PlayStop(void)
  776. {
  777. }
  778.  
  779.  
  780. BOOL VC_Init(void)
  781. {
  782.     int t;
  783.     for(t=0;t<32;t++){
  784.         vinf[t].current=0;
  785.         vinf[t].flags=0;
  786.         vinf[t].handle=0;
  787.         vinf[t].kick=0;
  788.         vinf[t].active=0;
  789.         vinf[t].frq=10000;
  790.         vinf[t].vol=0;
  791.         vinf[t].pan=(t&1)?0:255;
  792.     }
  793.  
  794. #ifdef __WATCOMC__
  795.     if(md_mode & DMODE_INTERP) md_mode&=~DMODE_INTERP;
  796.  
  797.     for(t=0;t<65;t++) volsel[t]=0;
  798.  
  799.     for(t=0;t<65;t++){
  800.         if(!(volsel[t]=getalias())) return 0;
  801.         setbase(volsel[t],(ULONG)voltab[t]);
  802.     }
  803. #endif
  804.  
  805.     return 1;
  806. }
  807.  
  808.  
  809. void VC_Exit(void)
  810. {
  811. #ifdef __WATCOMC__
  812.     int t;
  813.     for(t=0;t<65;t++){
  814.         if(volsel[t]) freedescriptor(volsel[t]);
  815.     }
  816. #endif
  817. }
  818.  
  819.  
  820. void VC_VoiceSetVolume(UBYTE voice,UBYTE vol)
  821. {
  822.     vinf[voice].vol=vol;
  823. }
  824.  
  825.  
  826. void VC_VoiceSetFrequency(UBYTE voice,ULONG frq)
  827. {
  828.     vinf[voice].frq=frq;
  829. }
  830.  
  831.  
  832. void VC_VoiceSetPanning(UBYTE voice,UBYTE pan)
  833. {
  834.     vinf[voice].pan=pan;
  835. }
  836.  
  837.  
  838. void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
  839. {
  840.     if(start>=size) return;
  841.  
  842.     if(flags&SF_LOOP){
  843.         if(repend>size) repend=size;    /* repend can't be bigger than size */
  844.     }
  845.  
  846.     vinf[voice].flags=flags;
  847.     vinf[voice].handle=handle;
  848.     vinf[voice].start=start;
  849.     vinf[voice].size=size;
  850.     vinf[voice].reppos=reppos;
  851.     vinf[voice].repend=repend;
  852.     vinf[voice].kick=1;
  853. }
  854.